package org.httpclient.service;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.Charsets;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/**
 * httpclient连接池服务
 * 
 * 在每次调用EntityUtils.toString(response.getEntity(),
 * charset)会调用instream.read()、instream.close()等方法,
 * instream的实现类为org.apache.http.conn.EofSensorInputStream,在每次通过instream.read()
 * 读取数据流后，都会判断流是否读取结束,并且判断连接可重用，把连接释放到连接池中，
 * 所以在每次调用get和post请求之后，不需要执行response.close()方法，这个方法会将连接关闭，失去连接池的作用。
 * 
 * @author chenfanglin
 * @date: 2018年8月15日 下午7:45:04
 */
@Service
public class HttpClientPoolService {

	private final Log log = LogFactory.getLog(HttpClientPoolService.class);

	@Autowired
	@Qualifier("httpClient")
	private CloseableHttpClient httpClient;

	@Autowired
	@Qualifier("requestConfig")
	private RequestConfig requestConfig;

	/**
	 * 执行GET请求
	 * 
	 * @param url
	 * @return
	 */
	public HttpResult doGet(String url) {
		return doGet(url, Charsets.UTF_8);
	}

	/**
	 * 执行GET请求
	 * 
	 * @param url
	 * @param charset
	 * @return
	 */
	public HttpResult doGet(String url, Charset charset) {
		// 创建httpClient对象
		CloseableHttpResponse response = null;
		HttpGet httpGet = new HttpGet(url);
		// 设置请求参数
		httpGet.setConfig(requestConfig);
		try {
			// 执行请求
			response = httpClient.execute(httpGet);
			return new HttpResult(response.getStatusLine().getStatusCode(),
					EntityUtils.toString(response.getEntity(), charset));
		} catch (Exception e) {
			log.error("执行GET请求异常:{}", e);
		}
		return null;
	}

	/**
	 * 带有参数的GET请求
	 * 
	 * @param url
	 * @param paramMap
	 * @return
	 */
	public HttpResult doGet(String url, Map<String, String> paramMap) {
		try {
			URIBuilder builder = new URIBuilder(url);
			for (String s : paramMap.keySet()) {
				builder.addParameter(s, paramMap.get(s));
			}
			return doGet(builder.build().toString(), Charsets.UTF_8);
		} catch (Exception e) {
			log.error("执行GET请求异常:{}", e);
		}
		return null;
	}

	/**
	 * 执行POST请求,表单提交的方式application/x-www-form-urlencoded
	 * 
	 * @param url
	 * @param paramMap
	 * @return
	 */
	public HttpResult doPost(String url, Map<String, String> paramMap) {
		HttpPost httpPost = new HttpPost(url);
		// 设置请求参数
		httpPost.setConfig(requestConfig);
		if (paramMap != null) {
			List<NameValuePair> parameters = new ArrayList<NameValuePair>();
			for (String s : paramMap.keySet()) {
				parameters.add(new BasicNameValuePair(s, paramMap.get(s)));
			}
			// 构建一个form表单式的实体
			UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, Charsets.UTF_8);
			// 将请求实体放入到httpPost中
			httpPost.setEntity(formEntity);
		}
		// 创建httpClient对象
		CloseableHttpResponse response = null;
		try {
			// 执行请求
			response = httpClient.execute(httpPost);
			return new HttpResult(response.getStatusLine().getStatusCode(), EntityUtils.toString(response.getEntity()));
		} catch (Exception e) {
			log.error("执行post请求异常:{}", e);
		}
		return null;
	}

	/**
	 * 执行POST请求
	 * 
	 * @param url
	 * @return
	 */
	public HttpResult doPost(String url) {
		return doPost(url, null);
	}

	/**
	 * 执行POST请求,提交JSON数据,application/json
	 * 
	 * @param url
	 * @param json
	 * @return
	 */
	public HttpResult doPostJson(String url, String json) {
		// 创建http POST请求
		HttpPost httpPost = new HttpPost(url);
		httpPost.setConfig(this.requestConfig);

		if (json != null) {
			// 构造一个请求实体
			StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
			// 将请求实体设置到httpPost对象中
			httpPost.setEntity(stringEntity);
		}
		CloseableHttpResponse response = null;
		try {
			// 执行请求
			response = this.httpClient.execute(httpPost);
			return new HttpResult(response.getStatusLine().getStatusCode(),
					EntityUtils.toString(response.getEntity(), Charsets.UTF_8));
		} catch (Exception e) {
			log.error("执行post请求异常:{}", e);
		}
		return null;
	}

}
